home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / raytrace / rayshade / graphtal.lzh / Graphtal.Amiga / Z_Buffer.C < prev    next >
C/C++ Source or Header  |  1993-08-26  |  8KB  |  334 lines

  1. /*
  2.  * Z_Buffer.C - zBuffer implementation for concave polygons.
  3.  *
  4.  * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
  5.  *                     University of Berne, Switzerland
  6.  * All rights reserved.
  7.  *
  8.  * This software may be freely copied, modified, and redistributed
  9.  * provided that this copyright notice is preserved on all copies.
  10.  *
  11.  * You may not distribute this software, in whole or in part, as part of
  12.  * any commercial product without the express consent of the authors.
  13.  *
  14.  * There is no warranty or other guarantee of fitness of this software
  15.  * for any purpose.  It is provided solely "as is".
  16.  *
  17.  */
  18.  
  19. #ifdef AMIGA_GCC
  20.     #include "string.h"
  21. #endif
  22.  
  23. #include <values.h>
  24. #include "Z_Buffer.h"
  25.  
  26. //___________________________________________________________ EdgeElement
  27.  
  28. struct EdgeElement {
  29.   real x;
  30.   real z;
  31. };
  32.  
  33. declareList(EdgeList, EdgeElement);
  34. implementList(EdgeList, EdgeElement);
  35.  
  36. //___________________________________________________________ Z_Buffer
  37.  
  38. Z_Buffer::Z_Buffer(ViewTransform* v, const rcString& msg, const rcString& oname)
  39. : view(v), remark(msg), ymin(resY), ymax(0), numPrimitives(0)
  40. {
  41.   resY = view->getResY();
  42.   resX = view->getResX(); 
  43.  
  44.   /*
  45.    * Create the yBuckets.
  46.    */
  47.   yBuckets = new EdgeList*[resY];
  48.   for (register int i=0; i<resY; i++) 
  49.     yBuckets[i] = new EdgeList(2);
  50.  
  51.   /*
  52.    * Create and initialize z-Buffer array.
  53.    */
  54.   zBuffer = new float[resY*resX];
  55.   for (i=0; i<resY*resX; i++)
  56.     zBuffer[i] = MAXFLOAT;
  57.  
  58.   /*
  59.    * Create and initialize pixmap.
  60.    */
  61.   pixmap = new unsigned char[resY*resX*3];
  62.   memset(pixmap, 0, resY*resX*3);
  63.  
  64.   /*
  65.    * Attach stream to outfile.
  66.    */
  67.   if (oname == "cout")
  68.     outfile = stdout;
  69.   else
  70.     outfile = fopen((const char*) oname, "w");
  71.  
  72.   if (outfile == NULL)
  73.     Error(ERR_PANIC, "can't open file " + oname);
  74. }
  75.   
  76. Z_Buffer::~Z_Buffer()
  77. {
  78.   delete view;
  79.   delete [] zBuffer;
  80.   delete [] pixmap;
  81.   for (register int i=0; i<resY; i++)
  82.     delete yBuckets[i];
  83.   delete [] yBuckets;
  84. }
  85.  
  86. void Z_Buffer::renderTriangle(const Color& color, const Vector& p1, 
  87.                   const Vector& p2, const Vector& p3)
  88. {
  89.   numPrimitives++;
  90.  
  91.   Vector tp1 = view->transformWorld2View(p1);
  92.   Vector tp2 = view->transformWorld2View(p2);
  93.   Vector tp3 = view->transformWorld2View(p3);
  94.  
  95.   /*
  96.    * Front plane clipping (z=0).
  97.    */
  98.   if (tp1[2] < 0 || tp2[2] < 0 || tp3[2] < 0)
  99.     return;
  100.  
  101.   Vector normal = (tp2-tp1)*(tp3-tp1);
  102.   if (!normal.normalize())
  103.     return;
  104.  
  105.   Vector lightVector = (tp1+tp2+tp3)/3;
  106.   calculateColor(color, normal, lightVector);
  107.  
  108.   tp1 = view->transformView2Screen(tp1);
  109.   tp2 = view->transformView2Screen(tp2);
  110.   tp3 = view->transformView2Screen(tp3);
  111.  
  112.   addEdge(tp1, tp2);
  113.   addEdge(tp2, tp3);
  114.   addEdge(tp3, tp1);
  115.  
  116.   render();
  117. }
  118.  
  119. void Z_Buffer::renderRectangle(const Color& color, const Vector& p1, const Vector& p2, 
  120.                    const Vector& p3, const Vector& p4)
  121. {
  122.   numPrimitives++;
  123.  
  124.   Vector tp1 = view->transformWorld2View(p1);
  125.   Vector tp2 = view->transformWorld2View(p2);
  126.   Vector tp3 = view->transformWorld2View(p3);
  127.   Vector tp4 = view->transformWorld2View(p4);
  128.  
  129.   /*
  130.    * Front plane clipping (z=0).
  131.    */
  132.   if (tp1[2] < 0 || tp2[2] < 0 || tp3[2] < 0 || tp4[2] < 0)
  133.     return;
  134.  
  135.   Vector normal = (tp2-tp1)*(tp4-tp1);
  136.   if (!normal.normalize())
  137.     return;
  138.  
  139.   Vector lightVector = (tp1+tp2+tp3+tp4)/4;
  140.   calculateColor(color, normal, lightVector);
  141.  
  142.   tp1 = view->transformView2Screen(tp1);
  143.   tp2 = view->transformView2Screen(tp2);
  144.   tp3 = view->transformView2Screen(tp3);
  145.   tp4 = view->transformView2Screen(tp4);
  146.  
  147.   addEdge(tp1, tp2);
  148.   addEdge(tp2, tp3);
  149.   addEdge(tp3, tp4);
  150.   addEdge(tp4, tp1);
  151.  
  152.   render();
  153. }
  154.  
  155. void Z_Buffer::renderPolygon(const Color& color, Polygon* p)
  156. {
  157.   numPrimitives++;
  158.  
  159.   /*
  160.    * Degenerate polygon?
  161.    */
  162.   if (p->numVertices() < 3)
  163.     return;
  164.  
  165.   /*
  166.    * Transform polygon to view space.
  167.    */
  168.   p->transform(view->getViewmat());
  169.  
  170.   /*
  171.    * Front plane clipping (z=0).
  172.    */
  173.   for (register long i=0; i<p->numVertices(); i++) 
  174.     if (p->vertex(i)[2] < 0)
  175.       return;
  176.  
  177.   Vector normal = p->normal();
  178.   if (normal.zero())
  179.     return;
  180.  
  181.   Vector lightVector;
  182.   for (i=0; i<p->numVertices(); i++)
  183.     lightVector += p->vertex(i);
  184.   lightVector /= p->numVertices();
  185.  
  186.   calculateColor(color, normal, lightVector);
  187.  
  188.   /*
  189.    * Add each edge of the polygon in the y-bucket structure.
  190.    */
  191.   Vector p1 = view->transformView2Screen(p->vertex(0));
  192.   Vector p2;
  193.   for (i=1; i<p->numVertices(); i++) {
  194.     p2 = view->transformView2Screen(p->vertex(i));
  195.     addEdge(p1, p2);
  196.     p1 = p2;
  197.   }
  198.   p2 = view->transformView2Screen(p->vertex(0));
  199.   addEdge(p1, p2);
  200.  
  201.   render();
  202.   delete p;
  203. }
  204.  
  205. void Z_Buffer::writePixmap()
  206. {
  207.   fprintf(outfile, "P6\n");
  208.   fprintf(outfile, "#%s\n", (const char*) remark);
  209.   fprintf(outfile, "%d\n%d\n255\n", resX, resY);
  210.   fwrite((char*)pixmap, resX*resY*3, 1, outfile);
  211.   fclose(outfile);
  212. }
  213.  
  214. void Z_Buffer::addEdge(const Vector& p1, const Vector& p2)
  215. {
  216.   const Vector& start = (p1[1] <= p2[1]) ? p1 : p2;
  217.   const Vector& end   = (p1[1] <= p2[1]) ? p2 : p1;
  218.  
  219.   int y1 = (int)(start[1]);
  220.   int y2 = (int)(end[1]);
  221.  
  222.   /*
  223.    * Horizontal edge, do nothing.
  224.    */
  225.   if (y1 == y2)
  226.     return;
  227.  
  228.   if (y1 < ymin) ymin = y1;
  229.   if (y2 > ymax) ymax = y2;
  230.  
  231.   /*
  232.    * Set up increments.
  233.    */
  234.   real x = start[0];
  235.   real z = start[2];
  236.   real denom = 1/(end[1]-start[1]);
  237.   real dx = (end[0]-x)*denom;
  238.   real dz = (end[2]-z)*denom;
  239.  
  240.   EdgeElement edgeElement;
  241.  
  242.   for (register int y=y1; y<y2; y++, x+=dx, z+=dz) {
  243.  
  244.     /*
  245.      * No clipping is done, so we have to check for out of screen space.
  246.      */
  247.     if (y<0) continue;
  248.     if (y>=resY) break;
  249.  
  250.     /*
  251.      * Create new EdgeElement entry in the Edgelist sorted by x.
  252.      */
  253.     edgeElement.x = x;
  254.     edgeElement.z = z;
  255.     register long i=0;
  256.     while (1) {
  257.       if (i>=yBuckets[y]->count()) {
  258.     yBuckets[y]->append(edgeElement);
  259.     break;
  260.       }
  261.       if (yBuckets[y]->item(i).x > x) {
  262.     yBuckets[y]->insert(i, edgeElement);
  263.     break;
  264.       }
  265.       i++;
  266.     }
  267.   }
  268. }
  269.  
  270. void Z_Buffer::render()
  271. {
  272.   int x1, x2, offset;
  273.   real dx, dz, z;
  274.   unsigned char* pixmapPos;
  275.  
  276.   if (ymin < 0)    ymin = 0;
  277.   if (ymax > resY) ymax = resY;
  278.  
  279.   for (register int y=ymin; y < ymax; y++) {
  280.     EdgeList* yBucket = yBuckets[y];
  281.  
  282.     offset = (resY-y)*resY;
  283.     for (register long i=0; i < yBucket->count(); i+=2) {
  284.       x1 = (int)(yBucket->item(i).x);
  285.       x2 = (int)(yBucket->item(i+1).x);
  286.  
  287.       if (x1 != x2) {
  288.     dx = yBucket->item(i+1).x - yBucket->item(i).x;
  289.     dz = (yBucket->item(i+1).z - yBucket->item(i).z)/dx;
  290.     z  = yBucket->item(i).z + (yBucket->item(i).x-x1)*dz; 
  291.  
  292.     for (register int x=x1; x < x2; x++) {
  293.       if (x >= 0 && x < resX) {
  294.         pixmapPos = pixmap + 3*(offset+x);
  295.         if (z < zBuffer[offset+x]) {
  296.           zBuffer[offset+x] = z;
  297.           *pixmapPos++ = (unsigned char)(R*255);
  298.           *pixmapPos++ = (unsigned char)(G*255);
  299.           *pixmapPos   = (unsigned char)(B*255);
  300.         }
  301.       }
  302.       z += dz;
  303.     }
  304.       }
  305.     }
  306.     yBucket->remove_all();
  307.   }
  308.  
  309.   ymin = resY;
  310.   ymax = 0;
  311. }
  312.  
  313. void Z_Buffer::calculateColor(const Color& color, const Vector& normal, const Vector& p)
  314. {
  315.   /*
  316.    * we don't do back face culling, so take absolute value of dot(light,normal).
  317.    *  our light sits at (0,0,0) = eye point (=> light vector = (0,0,0) - p)
  318.    */
  319.   Vector toEye = -p; toEye.normalize();
  320.   float intensity = fabs(toEye^normal);
  321.   
  322.   /*
  323.    * we don't calculate the intensity vor each vertex and take an 
  324.    *  average intensity => as a result the color ist usually too dark
  325.    *                    => add an ambient term.
  326.    */
  327.   intensity += 0.25; // add an ambient term, because intenisty
  328.   if (intensity>1) intensity = 1;
  329.  
  330.   R = color.r()*intensity;
  331.   G = color.g()*intensity;
  332.   B = color.b()*intensity;
  333. }
  334.